import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.geotools.data.*;
import org.geotools.data.postgis.PostgisNGDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.geometry.jts.GeometryBuilder;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.referencing.CRS;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.index.kdtree.KdNode;
import org.locationtech.jts.index.kdtree.KdTree;
import org.locationtech.jts.index.quadtree.Quadtree;
import org.locationtech.jts.io.WKTReader;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import utilityTools.GeoJsonUtiles;

import java.io.*;
import java.util.*;

//import org.wololo.jts2geojson.GeoJSONWriter;
//import org.geotools.data.geojson;

//进行GeoTools的一些基本接口的使用测试
public class GeotoolsOperation {

    private final String crsSource = "EPSG:4326";
    private final String crsTarget = "EPSG:3857";

    public void testUnion() throws Exception {
        String pathGeojson = "E:\\9.1GISData\\33333333.geojson";
        File fileSource = new File(pathGeojson);
        JSONObject jsonObjectSource = GeoJsonUtiles.getGeoJsonSource(fileSource);
        JSONArray featureArray = jsonObjectSource.getJSONArray("features");
        GeometryJSON geojsonFactory = new GeometryJSON();
        Reader readerStr = null;
        JSONObject featureInput = featureArray.getJSONObject(0);
        readerStr = new StringReader(featureInput.toJSONString());
        Geometry geoInput = geojsonFactory.read(readerStr);//虽然是整个feature的字符串，但也可以直接读取到几何结果
        JSONObject featureOther = featureArray.getJSONObject(1);
        readerStr = new StringReader(featureOther.toJSONString());
        Geometry geoOther = geojsonFactory.read(readerStr);
        Geometry geoOutput = geoInput.union(geoOther);
        if (geoOutput.isEmpty()) {
            System.out.println("union结果几何是空");
        }
        System.out.println("几何结果集：" + geoOutput.toText());
        String rrrr = "E:\\9.1GISData\\demounion.geojson";
        File filerrrrr = new File(rrrr);
        OutputStream osrrrr = new FileOutputStream(filerrrrr);
        geojsonFactory.write(geoOutput, osrrrr);
        osrrrr.flush();
        osrrrr.close();
    }

    public void testGeometryWkt() throws Exception {
        String wktPolygon_Other = "POLYGON((77.457034547465611 43.949983701892023, " +
                "88.086932895925074 44.128138422815923, 88.086932895925074 44.128138422815923, " +
                "96.163280244475274 40.208734562490093, 93.550344337591383 36.051791074265722, " +
                "91.353102779529934 30.172685283776975, 82.207827105436323 25.837587074628704, " +
                "75.437947710328075 32.666851376711591, 77.457034547465611 43.949983701892023))";
        String wktPolygon_Input = "POLYGON((117.110858 40.70836,117.286401 40.660719,"
                + "117.389879 40.228141,117.389879 40.5617,117.110858 40.70836))";
        GeometryFactory geoFactory = JTSFactoryFinder.getGeometryFactory();
        WKTReader wktReader = new WKTReader(geoFactory);
        Geometry geometryNew = wktReader.read(wktPolygon_Input);
//        GeometryJSON gjFactory = new GeometryJSON();
//        String strGeometry=gjFactory.toString(geometryNew);
//        System.out.println("原始Geometry的Json字符串："+strGeometry);
//        JSONObject jjGeo=JSONObject.parseObject(strGeometry);
//        System.out.println("包装后获取的coordinates："+jjGeo.getString("coordinates"));
//        System.out.println(geometryNew.getNumPoints());
////        System.out.println(geometryNew.getCoordinates().toString());//这是是类型，而不是值
//        for (Coordinate coordinate : geometryNew.getCoordinates()) {
//            System.out.println(coordinate.toString());
//
//        }
        String tmp = GeoJsonUtiles.convertGeometry2Wkt(geometryNew);
        System.out.println(tmp);
    }

    public void testReadWkt() throws Exception {
        String wktPolygon = "POLYGON((117.110858 40.70836,117.286401 40.660719," +
                "117.389879 40.228141,117.389879 40.5617,117.110858 40.70836))";
        String wktPoint = "POINT(117.23852 34.78695)";
        String wktCollection = "GEOMETRYCOLLECTION(POINT(116.23852 33.78695),POINT(117.23852 34.78695),POINT(118.23852 35.78695))";
        WKTReader reader = new WKTReader();
        Geometry geometryNew = reader.read(wktPoint);
        System.out.println("几何类型：" + geometryNew.getGeometryType());
        Geometry geo2 = reader.read(wktCollection);
        if (geo2 instanceof GeometryCollection) {
            System.out.println("Collection读取后的类型：" + geo2.getGeometryType());
        } else {
            System.out.println("不能使用instanceof判断");
        }
    }

    public void test求两点距离() throws Exception {
        String pathShp = "E:\\9.1GISData\\spatialautocorrelation\\pointSpatialAutoCorrelation2.shp";
        SimpleFeatureSource fs = (SimpleFeatureSource) ShpfileReader.getShpfile2(pathShp, "utf-8");
        SimpleFeatureIterator itSource = fs.getFeatures().features();
        List<Geometry> geolist = new ArrayList<>();
        while (itSource.hasNext()) {
            SimpleFeature sf = itSource.next();
            geolist.add(((Geometry) sf.getDefaultGeometry()));
        }
        System.out.println("距离计算结果输出：");
        //直接按度来计算
//        System.out.println(geolist.get(0).getCoordinates()[0].getX()+";"+geolist.get(0).getCoordinates()[0].getY());
//        System.out.println(geolist.get(1).getCoordinates()[0].getX()+";"+geolist.get(1).getCoordinates()[0].getY());
//        double disDegree=geolist.get(0).distance(geolist.get(1));
//        System.out.println(disDegree);//计算的结果是弧度值
//        double disMeter=disDegree/((2*Math.PI*6371004)*360);//这样的结果不对，必须先投影再计算
//        System.out.println(disMeter);
        //坐标参考内容获取
        CoordinateReferenceSystem crsSource = fs.getSchema().getCoordinateReferenceSystem();
        System.out.println(crsSource.getName().getCode());//GCS_WGS_1984
        System.out.println(crsSource.getCoordinateSystem().getName().getCode());//GCS_WGS_1984
        System.out.println(crsSource.getName().getCodeSpace());//null
        System.out.println(CRS.toSRS(crsSource));
        CoordinateReferenceSystem crsNew = CRS.decode(crsSource.getName().getCode());
        System.out.println(crsNew.getName());
        //转换后再计算
        double[] xyGeo1 = new double[]{geolist.get(0).getCoordinates()[0].getX(), geolist.get(0).getCoordinates()[0].getY()};
        double[] xyGeo2 = new double[]{geolist.get(1).getCoordinates()[0].getX(), geolist.get(1).getCoordinates()[0].getY()};
        double[] xyTransed1 = CoordTransformService.crsTransform("EPSG:4326", "EPSG:3857", xyGeo1[0], xyGeo1[1], true);
        double[] xyTransed2 = CoordTransformService.crsTransform("EPSG:4326", "EPSG:3857", xyGeo2[0], xyGeo2[1], true);
        double disCalced = Math.sqrt(Math.pow(xyTransed1[0] - xyTransed2[0], 2) + Math.pow(xyTransed1[1] - xyTransed2[1], 2));
        System.out.println("手工计算结果：" + disCalced);
        Geometry geoTrans1 = CoordTransformService.crsTransform("EPSG:4326", "EPSG:3857", geolist.get(0));
        Geometry geoTrans2 = CoordTransformService.crsTransform("EPSG:4326", "EPSG:3857", geolist.get(1));
        double disTransed = geoTrans1.distance(geoTrans2);
        System.out.println("GeoTools计算结果：" + disTransed);
    }

    public void test空间权重矩阵() throws Exception {
        String pathShp = "E:\\9.1GISData\\spatialautocorrelation\\pointSpatialAutoCorrelation2.shp";
        SimpleFeatureSource fs = (SimpleFeatureSource) ShpfileReader.getShpfile2(pathShp, "utf-8");
        SimpleFeatureIterator itSource = fs.getFeatures().features();
        List<Geometry> geolist = new ArrayList<>();
        while (itSource.hasNext()) {
            SimpleFeature sf = itSource.next();
            geolist.add(((Geometry) sf.getDefaultGeometry()));
        }
        Geometry[] geometries = geolist.stream().toArray(Geometry[]::new);
        double[][] swmSource = buildSWM(geometries);
        double[] minValuesPerRow = getThresholdDistance(swmSource);
        Arrays.sort(minValuesPerRow);
        for (double v : minValuesPerRow) {
            System.out.println(v);
        }
        System.out.println("默认阈值是：" + minValuesPerRow[minValuesPerRow.length - 1]);
//        //原始空间权重矩阵
//        Double[][] swmSource = buildSpatialWightMatrixByInverseDistance(geometries);
//        //设置最小临近点的个数
//        int nearPnts=14;
//        Double[] result=getmydata(swmSource,nearPnts);
//        Arrays.sort(result);//对结果进行升序排列
//        System.out.println("最小临近点为{"+nearPnts+"}个的结果");
//        for (int i = result.length-1; i >result.length-10; i--) {
//            System.out.println(result[i]);
//        }
//        System.out.print(System.lineSeparator());//换行符的打印
//        Double ttt=0.0d;
//        for (Double perMin : result) {
//            ttt+=perMin;
//        }
//        System.out.println("平均值是："+ttt / result.length);
    }

    private Double[][] buildSpatialWightMatrixByInverseDistance(Geometry[] geometriesSource) {
        Envelope clipEnvelpoe = new Envelope();
        int lengthOfMatrix = geometriesSource.length;
//        double disThreshold = 51473.9184;//空间权重矩阵计算时的距离阈值，大于它的都赋值为0
        Double[][] spatialWightMatrix = new Double[lengthOfMatrix][lengthOfMatrix];
        //‘从左至右，从上至下’的顺序去填充空间权重矩阵
        for (int i = 0; i < lengthOfMatrix; i++) {
            Geometry iGeo = CoordTransformService.crsTransform(crsSource, crsTarget, geometriesSource[i]);
            clipEnvelpoe.expandToInclude(iGeo.getCoordinate());
            for (int j = i; j < lengthOfMatrix; j++) {
                if (j == i) {
                    spatialWightMatrix[i][j] = 999999.999999d;//矩阵的斜线上值为0
                } else {
                    Geometry jGeo = CoordTransformService.crsTransform(crsSource, crsTarget, geometriesSource[j]);
                    double ij = iGeo.distance(jGeo);
                    spatialWightMatrix[i][j] = ij;
                    spatialWightMatrix[j][i] = ij;
                }
            }
        }
        System.out.println("坐标转换后的Extent-max值：" + clipEnvelpoe.maxExtent());
        System.out.println("坐标转换后的Extent-min值：" + clipEnvelpoe.minExtent());
        return spatialWightMatrix;
    }

    private Double[] getmydata(Double[][] matrixInput, int nearNums) {
        Double[][] midddleMatrix = matrixInput.clone();
        Double[] rslt = new Double[matrixInput.length];//创建一个行数长度的数组
        for (int rowIndex = 0; rowIndex < midddleMatrix.length; rowIndex++) {
            Arrays.sort(midddleMatrix[rowIndex]);//对该行进行升序排列
            //打印前nearNums个要素
            for (int clnIndex = 0; clnIndex < nearNums; clnIndex++) {
                System.out.print(midddleMatrix[rowIndex][clnIndex] + "  ");
            }
            System.out.print(System.lineSeparator());
            //获取最小临近点个数的距离
            rslt[rowIndex] = midddleMatrix[rowIndex][nearNums - 1];
        }
        return rslt;
    }

    private double[] getThresholdDistance(double[][] swmSource) {
        int lenghtMatrix = swmSource.length;
        double[] minValuesOfPerRow = new double[lenghtMatrix];
        for (int i = 0; i < lenghtMatrix; i++) {
            Arrays.sort(swmSource[i]);
            for (int j = 0; j < 3; j++) {
                System.out.println(swmSource[i][j]);
            }
            minValuesOfPerRow[i] = swmSource[i][1];//排序后，一般第二个元素是最小值
        }
        return minValuesOfPerRow;
//        Arrays.sort(minValuesOfPerRow);
//        return minValuesOfPerRow[lenghtMatrix - 1];//返回所有最小值中的最大值
    }

    private double[][] buildSWM(Geometry[] geometriesSource) {
        int lengthOfMatrix = geometriesSource.length;
//        double disThreshold = 51473.9184;//空间权重矩阵计算时的距离阈值，大于它的都赋值为0
        double[][] swm = new double[lengthOfMatrix][lengthOfMatrix];
        //‘从左至右，从上至下’的顺序去填充空间权重矩阵
        for (int i = 0; i < lengthOfMatrix; i++) {
            Geometry iGeo = CoordTransformService.crsTransform(crsSource, crsTarget, geometriesSource[i]);
            for (int j = i + 1; j < lengthOfMatrix; j++) {
                Geometry jGeo = CoordTransformService.crsTransform(crsSource, crsTarget, geometriesSource[j]);
                //求欧氏距离
                double ij = iGeo.distance(jGeo);
                swm[i][j] = ij;
                swm[j][i] = ij;
            }
        }
        return swm;
    }

    /*
     * 计算两个Geometry的距离
     * 1.直接使用Geometry的distance方法，在‘面’类型下，计算的是两个面上最近点的距离；
     * 2.Geometry的getCentroid方法获取的是质心；而getInterior方法获取的点不一定在面内部（有可能在外部）；
     *   因此在使用中，可以使用getCentroid去获取多边形的中心（因为此时是无密度的）
     * */
    public void calcDistance() throws Exception {
        //获取原始图形数据
        String pathShp_Polygon = "E:\\9.1GISData\\polygon2single.shp";
        SimpleFeatureSource sfs = (SimpleFeatureSource) ShpfileReader.getShpfile2(pathShp_Polygon, "utf-8");
        SimpleFeatureIterator itSource = sfs.getFeatures().features();
        System.out.println(sfs.getSchema().getGeometryDescriptor().getType().getName().toString());
        List<Geometry> geolist = new ArrayList<>();
        int cntTest = 0;
        while (itSource.hasNext()) {
            SimpleFeature feature = itSource.next();
            System.out.println(feature.getDefaultGeometryProperty().getType().getBinding().getTypeName());
            System.out.println(feature.getDefaultGeometryProperty().getType().getName());
            System.out.println(feature.getType().getTypeName());//这个是获取的shp的名字
            if (cntTest < 3) {
                String geoName = feature.getAttribute("name").toString();
                System.out.println(geoName);
                geolist.add(((Geometry) feature.getDefaultGeometry()));
            } else {
                break;
            }
            cntTest++;
        }
        //开始计算测试
        for (int idx = 0; idx < geolist.size(); idx++) {
            Geometry iGeo = geolist.get(idx);
            Point iPnt = iGeo.getCentroid();
            System.out.println("质心坐标[原始]：" + iPnt.getCoordinate().getX() + "," + iPnt.getCoordinate().getY());//质心坐标打印出来是没有问题的
            double[] iCoords = CoordTransformService.crsTransform(crsSource, crsTarget, iPnt.getX(), iPnt.getY(), false);
            System.out.println("A使用xy方式转换：" + iCoords[0] + ";" + iCoords[1]);
            Geometry iPntConverted = CoordTransformService.crsTransform(crsSource, crsTarget, iPnt);
            System.out.println("使用几何方式转换：" + iPntConverted.getCoordinate().getX() + "," + iPntConverted.getCoordinate().getY());
            System.out.println("====================");
            Geometry jGeo = geolist.get(idx + 1);
            Point jPnt = jGeo.getCentroid();
            System.out.println("质心坐标[原始]：" + jPnt.getX() + "," + jPnt.getY());
            double[] jCoords = CoordTransformService.crsTransform(crsSource, crsTarget, jPnt.getX(), jPnt.getY(), false);
            System.out.println("B使用xy方式转换：" + jCoords[0] + ";" + jCoords[1]);
            double dis = iGeo.distance(jGeo);//源码：计算的是两个几何体上最近点的距离
            System.out.println("直接用面几何计算的距离：" + dis);
            double disCalc = Math.sqrt(Math.pow(iCoords[0] - jCoords[0], 2) + Math.pow(iCoords[1] - jCoords[1], 2));
            System.out.println("使用坐标计算的距离是：" + disCalc);
            break;
        }
    }

    public void test几何类型判断() throws Exception {
        String pathShp = "E:\\9.1GISData\\spatialautocorrelation\\pointSpatialAutoCorrelation.shp";
        SimpleFeatureSource sfs = (SimpleFeatureSource) ShpfileReader.getShpfile2(pathShp, "utf-8");
        GeometryType typeGeo = sfs.getSchema().getGeometryDescriptor().getType();
        System.out.println(typeGeo.getClass());//org.geotools.feature.type.GeometryTypeImpl
        System.out.println("原始类型字符串：" + typeGeo.getBinding());
        if (typeGeo.getBinding().equals(Geometry.class)) {
            System.out.println("可以等于Geometry");
        }
        if (Geometry.class.isAssignableFrom(typeGeo.getBinding())) {
            System.out.println("可以执行判断");
        }
        if (typeGeo.getBinding().equals(Point.class)) {
            System.out.println("是Point");
        } else if (typeGeo.getBinding().equals(Polygon.class) || typeGeo.getClass().equals(MultiPolygon.class)) {
            System.out.println("是Polygon");
        } else {
            System.out.println("不支持的几何类型");
        }
    }

    public void getDemoGeometry() throws Exception {
        String pathGeojson = "E:\\9.1GISData\\geojson-polygontwoSingle.geojson";
        String pathGeojson_Pnt = "E:\\9.1GISData\\geojson_point.json";
        File fileGeojson = new File(pathGeojson);
        JSONObject source = GeoJsonUtiles.getGeoJsonSource(fileGeojson);
        JSONArray feaArray = source.getJSONArray("features");
        JSONObject joProperties = feaArray.getJSONObject(0).getJSONObject("properties");
        System.out.println(joProperties.getString("name"));
        JSONObject joGeo = feaArray.getJSONObject(0).getJSONObject("geometry");
        System.out.println("直接获取geojson的Geometry的字符串：" + joGeo.toJSONString());
        String wktGeo = GeoJsonUtiles.convertGeometry2Wkt(joGeo);
        System.out.println("转换为wkt之后的字符串：" + wktGeo);
        //===============================
        String wktGeoCollection = "geometrycollection(point(116.405285 39.904989),point(117.190182 39.125596)," +
                "point(114.502461 38.045474),point(112.549248 37.857014))";
        WKTReader wktReader = new WKTReader();
        Geometry geoFromWKT = wktReader.read(wktGeo);
        double[] boundaryCoords = getBoundaryCoordsSelf(geoFromWKT.getCoordinates());
        System.out.println("外接矩形 ：" + geoFromWKT.getEnvelope().toText());//获取的不是最小外接矩形，而是由最大、最小坐标组成的一个矩形
        System.out.println("面积1：" + geoFromWKT.getEnvelope().getArea());
        Envelope envelopeMid = geoFromWKT.getEnvelopeInternal();
        System.out.println("外接矩形2：" + JTS.toGeometry(envelopeMid).toText());
        System.out.println("面积2：" + envelopeMid.getArea());
        //==============================
        GeometryJSON gjFactory = new GeometryJSON();
        System.out.println(gjFactory.toString(geoFromWKT.getEnvelope()));
        System.out.println("执行完毕");
    }

    private double[] getBoundaryCoordsSelf(Coordinate[] coordinates) {
        List<Double> xValues = new ArrayList<Double>();
        List<Double> yValues = new ArrayList<Double>();
        for (Coordinate perCoord : coordinates) {
            xValues.add(perCoord.getX());
            yValues.add(perCoord.getY());
        }
        xValues.sort(new Comparator<Double>() {
            @Override
            public int compare(Double o1, Double o2) {
                return o1 > o2 ? 1 : -1;
            }
        });//这种形式时：进行升序排列
        System.out.println("X_Max:" + xValues.get(0));
        System.out.println("X_Min:" + xValues.get(xValues.size() - 1));
        yValues.sort(new Comparator<Double>() {
            @Override
            public int compare(Double o1, Double o2) {
                return o1 > o2 ? 1 : -1;
            }
        });
        System.out.println("Y_Max:" + yValues.get(0));
        System.out.println("Y_Min:" + yValues.get(yValues.size() - 1));
        return new double[]{xValues.get(0), yValues.get(0), xValues.get(xValues.size() - 1), yValues.get(yValues.size() - 1)};
    }

    public void testEPSG坐标系() throws Exception {
        CoordinateReferenceSystem crs4490 = CRS.decode("EPSG:4490", true);
        System.out.println("4490:" + crs4490.toWKT());
        System.out.println(crs4490.getName().getCode());
        System.out.println("00000===00000");
        String prj4490 = CRS.getProjectedCRS(crs4490) == null ? "无投影" : CRS.getProjectedCRS(crs4490).toWKT();
        System.out.println("4490投影" + prj4490);
        CoordinateReferenceSystem crs4479 = CRS.decode("EPSG:4479", true);
        System.out.println("4479:" + crs4479.toWKT());
        String prj4479 = CRS.getProjectedCRS(crs4479) == null ? "无投影" : CRS.getProjectedCRS(crs4479).toWKT();
        System.out.println("4479投影：" + prj4479);
        CoordinateReferenceSystem crs4480 = CRS.decode("EPSG:4480", true);
        System.out.println(crs4480.getName().getCode());
//        System.out.println("4480:"+crs4480.toWKT());//这个是无法打印出来的。
    }

    public void testxy2vector() {
        try {
            mydelete xyToVectorService = new mydelete();
            String pathCSV = "E:\\9.1GISData\\xytovector\\pointofprovince3.csv";
            String xField = "X";
            String yField = "Y";
            String shpPath = xyToVectorService.openCSVWithExcelMode(pathCSV, xField, yField, "UTF-8", "EPSG:4326");
            System.out.println("生成的shp文件是：" + shpPath);
        } catch (Exception error) {
            System.out.println("执行错误：" + error.getMessage());
            error.printStackTrace();
        }
    }

    FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2();

    public void test普通空间查询(){
        try {
            //打开原始点集数据
            String filePath = "E:\\9.1GISData\\idwTest\\countcenterofshanxi.shp";
            SimpleFeatureSource sfs=ShpfileReader.getShpfile2(filePath,"GBK");
            String geoAttrName=sfs.getSchema().getGeometryDescriptor().getLocalName();
            String tblName=sfs.getSchema().getTypeName();
            System.out.println("获取的TypeName是："+tblName);
            long timeStart=System.currentTimeMillis();
            //创建搜索多边形
            double rDegree = 0.3;
            Polygon calcCircle = createCircle(109.0624, 34.0579, rDegree);
            Filter geoFilter=filterFactory.intersects(filterFactory.property(geoAttrName),filterFactory.literal(calcCircle));
            //创建Query对象
            Query queryByGeo=new Query(tblName);
            queryByGeo.setFilter(geoFilter);
            SimpleFeatureCollection sfc= sfs.getFeatures(queryByGeo);
            System.out.println("查询结果是："+sfc.size());
            long timeEnd=System.currentTimeMillis();
            sfs.getDataStore().dispose();//这一句就是shp文件的释放方式
            System.out.println("[普通查询]耗时:" + (timeEnd-timeStart) / 1000);
        }catch (Exception error){
            System.out.print("执行失败：");
            System.out.println(error.getMessage());
        }
    }

    public void test四叉树空间索引() {
        try {
            //打开原始点集数据
            String filePath = "E:\\9.1GISData\\idwTest\\countcenterofshanxi.shp";
            SimpleFeatureCollection sfc=ShpfileReader.getShpfile2(filePath,"GBK").getFeatures();
            SimpleFeatureIterator iterator = sfc.features();
            System.out.println("shp的坐标系是："+System.lineSeparator()+sfc.getSchema().getCoordinateReferenceSystem().toWKT());
            //建立四叉树索引
            int flag=0;
            Quadtree quadtree = new Quadtree();
            Date start = new Date();
            while (iterator.hasNext()) {
                SimpleFeature ft = iterator.next();
                Point pntSource = (Point) ft.getDefaultGeometry();
                quadtree.insert(pntSource.getEnvelopeInternal(), ft);
                if (flag==0) {
                    System.out.println("点的Envelope的面积："+pntSource.getEnvelopeInternal().getArea());
                    flag++;
                }
            }
            System.out.println("[建立四叉树索引]耗时:" + (new Date().getTime() - start.getTime()) / 1000);
            //建立模拟搜索框
            start = new Date();
            //以下4行是什么含义，没有理解
//            Envelope search = new Envelope(pntSearch.getCoordinate());
//            OctagonalEnvelope searchGeom = new OctagonalEnvelope(pntSearch.getCoordinate());
//            searchGeom.expandBy(0.001);
//            search.expandBy(0.001);
            double rDegree = 0.001;//30000/1000*KILOMETRE_VS_DEGREE;

            //建立一个半径30000m的圆作为搜索区域
            GeometryBuilder geoBuilder = new GeometryBuilder();
            Polygon polygonSearch = geoBuilder.circle(109.0624, 34.5079, rDegree, 32);
            Polygon calcCircle = createCircle(109.0624, 34.0579, rDegree);
            System.out.println("圆的面积是：" + calcCircle.getArea());
            System.out.println("圆的Envelope的面积是："+calcCircle.getEnvelopeInternal().getArea());
            //这种建立搜索范围的方式不可行
//            Envelope ttt=new Envelope();
//            ttt.expandBy(20000);
            //执行搜索
            List result = quadtree.query(calcCircle.getEnvelopeInternal());
            for (Object ob : result) {
                SimpleFeature sft = (SimpleFeature) ob;
                System.out.println(sft.getAttribute("NAME").toString());
            }
            System.out.println("查询结果数量：" + result.size());

            System.out.println("总数据量:" + quadtree.size() + "条");
            System.out.println("四叉树深度：" + quadtree.depth());
            System.out.println("四叉树树索引查找耗时:" + (new Date().getTime() - start.getTime()));
        } catch (Exception error) {
            System.out.println("执行出错：" + error.getMessage());
        }
    }

    public void testKdTree索引(){
        try {
            //打开原始点集数据
            String filePath = "E:\\9.1GISData\\idwTest\\countcenterofshanxi.shp";
            SimpleFeatureCollection sfc=ShpfileReader.getShpfile2(filePath,"GBK").getFeatures();
            SimpleFeatureIterator iterator = sfc.features();
            KdTree kdTree=new KdTree();
            //建立索引
            while (iterator.hasNext()) {
                SimpleFeature ft = iterator.next();
                Point pntSource = (Point) ft.getDefaultGeometry();
                kdTree.insert(pntSource.getCoordinate());
            }
            //执行查询
            double rDegree = 0.2;
            Polygon calcCircle = createCircle(109.0624, 34.0579, rDegree);
            List rsltQuery= kdTree.query(calcCircle.getEnvelopeInternal());
            System.out.println(rsltQuery.get(0).getClass().toString());
            KdNode node= ((KdNode) rsltQuery.get(0));
            Object nobj= node.getData();
            if (nobj==null) {
                //kdtree的getData是否有值，在于执行insert时使用了那个方法
                //kdtree的node只能获取到坐标信息
                System.out.println("getData结果为空");
            }
            System.out.println(node.getCoordinate().toString());
//            for (Object o : rsltQuery) {
//                System.out.println(o.getClass().toString());
//            }
            System.out.println("查询结果数量为："+rsltQuery.size());
        }catch (Exception error){
            System.out.println("执行失败");
            System.out.println(error.getMessage());
        }
    }
    private GeometryFactory geometryFactory = new GeometryFactory();

    private Polygon createCircle(double x, double y, final double RADIUS) {
        final int SIDES = 32; // 确定边数
        Coordinate coords[] = new Coordinate[SIDES + 1];
        for (int i = 0; i < SIDES; i++) {
            double angle = ((double) i / (double) SIDES) * Math.PI * 2.0;
            double dx = Math.cos(angle) * RADIUS;
            double dy = Math.sin(angle) * RADIUS;
            coords[i] = new Coordinate((double) x + dx, (double) y + dy);
        }
        coords[SIDES] = coords[0];
        LinearRing ring = geometryFactory.createLinearRing(coords); // 画一个环线
        Polygon polygon = geometryFactory.createPolygon(ring, null); // 生成一个面
        return polygon;
    }

    public void test判断String是wkt或geojson() {
        Geometry geoResult;
        try {
            String strWKT = "POLYGON((117.110858 40.70836,117.286401 40.660719,117.389879 40.228141," +
                    "117.389879 40.5617,117.110858 40.70836))";
            String strGeojson = "{ \"type\": \"MultiPolygon\", " +
                    "\"coordinates\": [ [ [ [ 115.183823242330959, 36.029383221281918 ], [ 115.204938777480578, 36.027892712918415 ], " +
                    "[ 115.204938777480578, 36.027892712918415 ], [ 115.212515528328382, 36.015596018919524 ], " +
                    "[ 115.20667770390466, 36.000815144314792 ], [ 115.184941123603593, 35.992865766376113 ], " +
                    "[ 115.168918158695945, 36.008267686132299 ], [ 115.183823242330959, 36.029383221281918 ] ] ] ] }";
            WKTReader wktReader = new WKTReader();
            geoResult = wktReader.read(strGeojson);
            if (geoResult != null) {
                System.out.println("面积是：" + geoResult.getArea());
            } else if (JSONObject.isValid(strGeojson)) {
                GeometryJSON geoJSON = new GeometryJSON();
                geoResult = geoJSON.read(new StringReader(strGeojson));
                System.out.println("面积是：" + geoResult.getArea());
            } else {
                throw new IllegalArgumentException("The input value is illegal, Please checkout and enter a valid WKT or GeoJSON.");
                //输入值既不是合法的WKT字符串，也不是合法的GeoJSON字符串，请检查后重新输入！
            }
        } catch (Exception error) {
            System.out.println("转换出错");
            error.printStackTrace();
        }
    }

    public void test获取PostGIS数据() throws IOException {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put(PostgisNGDataStoreFactory.DBTYPE.key, "postgis");
        params.put(PostgisNGDataStoreFactory.HOST.key, "localhost");
        params.put(PostgisNGDataStoreFactory.PORT.key, 5432);
        params.put(PostgisNGDataStoreFactory.DATABASE.key, "gisdb");
        params.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");
        params.put(PostgisNGDataStoreFactory.USER.key, "postgres");
        params.put(PostgisNGDataStoreFactory.PASSWD.key, "123456");
        DataStore dsSource= DataStoreFinder.getDataStore(params);
        //针对PostGIS类型的数据，不能像shp那样，直接使用getTypeNames()[0]的方式，因为获取的是整个库中的所有空间表(还包含其他部分表)
        String[] typeNamesSource=dsSource.getTypeNames();
        for (String perTypeName : typeNamesSource) {
            System.out.println(perTypeName);
            System.err.println(perTypeName);//可以将错误以红色打印在控制台上
        }
//        String layerName= dsSource.getTypeNames()[0];
//        System.out.println("图层名称："+layerName);
    }

    //geojson导入PG
    public boolean importGeojson2PG(String geojsonpath, String tablename) throws IOException {
        //还需要验证一下路径的有效性
        DataStore pgDatastore = null;//创建PG的DataStore对象//postgisDataStore.getInstance();
        FeatureJSON featureJSON = new FeatureJSON();
        FeatureCollection featureCollection = featureJSON.readFeatureCollection(new FileInputStream(geojsonpath));
        SimpleFeatureType geojsontype = (SimpleFeatureType) featureCollection.getSchema();
        SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
        typeBuilder.init(geojsontype);
        typeBuilder.setName(tablename);
        SimpleFeatureType newtype = typeBuilder.buildFeatureType();
        pgDatastore.createSchema(newtype);

        FeatureIterator iterator = featureCollection.features();
        FeatureWriter<SimpleFeatureType, SimpleFeature> featureWriter = pgDatastore.getFeatureWriterAppend(tablename, Transaction.AUTO_COMMIT);

        while (iterator.hasNext()) {
            Feature feature = iterator.next();
            SimpleFeature simpleFeature = featureWriter.next();
            Collection<Property> properties = feature.getProperties();
            Iterator<Property> propertyIterator = properties.iterator();
            while (propertyIterator.hasNext()) {
                Property property = propertyIterator.next();
                simpleFeature.setAttribute(property.getName().toString(), property.getValue());
            }
            featureWriter.write();
        }
        iterator.close();
        featureWriter.close();
        pgDatastore.dispose();
        return true;
    }

    //PG导出为geojson
    /*
    * 这里应该支持属性的选择，即PG导出时，要能够勾选哪些字段导出
    * */
    public boolean exportPG2Geojson(String tablename, String geojsonPath) throws IOException, FactoryException {
        DataStore pgDatastore = null;//创建PG对象//postgisDataStore.getInstance();
        FeatureSource featureSource = pgDatastore.getFeatureSource(tablename);
        FeatureCollection featureCollection = featureSource.getFeatures();
        FeatureJSON featureJSON = new FeatureJSON();
        File file = new File(geojsonPath);
        if (!file.exists()) {
            file.createNewFile();
        }
        OutputStream outputStream = new FileOutputStream(file, false);
        featureJSON.writeFeatureCollection(featureCollection, outputStream);
        pgDatastore.dispose();
        return true;
    }

}
